/*
 * File:    Registry.java
 * Created: 19-Jan-2008
 * Version: $Id$
 *
 * COPYRIGHT (C) 2008, BitgateSoftware, LLC.  All Rights Reserved.
 * Released under the Creative Commons License version 2.5
 *
 * software@bitgatesoftware.com
 */

package com.bitgate.util.sql;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;

import com.bitgate.util.config.Config;
import com.bitgate.util.config.Constants;
import com.bitgate.util.db.DBException;
import com.bitgate.util.db.Driver;

import static com.bitgate.util.debug.Debug.debug;
import static com.bitgate.util.debug.Debug.warning;
import static com.bitgate.util.debug.Debug.isDebugEnabled;

public class Registry
{
	private static final Registry _default = new Registry();
	
	private class RegistryContainer {
		private final String url;
		private final String username;
		private final String password;
		private final Driver dbDriver;
		
		public RegistryContainer(Driver dbDriver, String url, String username, String password) {
			this.dbDriver = dbDriver;
			this.url = url;
			this.username = username;
			this.password = password;
		}
		
		public RegistryContainer(Driver dbDriver, String url) {
			this.dbDriver = dbDriver;
			this.url = url;
			this.username = null;
			this.password = null;
		}
		
		public Connection getConnection() throws DBException {
			if (username != null && !username.equals("")) {
				return dbDriver.get(url, username, password);
			}
			
			return dbDriver.get(url);
		}
	}
	
	private HashMap<String, RegistryContainer> jdbcRegistry;
	
	public Registry() {
		String databaseFilename = System.getProperty("database.config");
		
		if (databaseFilename == null) {
			databaseFilename = "conf/defaults/database.xml";
		}
		
		Config.getDefault().register(databaseFilename, "database");
		jdbcRegistry = new HashMap<String, RegistryContainer>();
		
		init();
	}
	
	private void init() {
		int numObjects = Integer.parseInt(Config.getDefault().parseConfig("database", "count(" + Constants.DATABASE_OBJECT.get() +
				")"));
		
		for(int i = 1; i < (numObjects + 1); i++) {
			String dbType = Config.getDefault().parseConfig("database", Constants.DATABASE_OBJECT.get(i) + "/@type");
			String dbName = Config.getDefault().parseConfig("database", Constants.DATABASE_OBJECT.get(i) + "/@name");
			String dbUrl = Config.getDefault().parseConfig("database", Constants.DATABASE_OBJECT.get(i) +
					"/property[@type='database.url']/@value");
			String dbUsername = Config.getDefault().parseConfig("database", Constants.DATABASE_OBJECT.get(i) +
					"/property[@type='database.username']/@value");
			String dbPassword = Config.getDefault().parseConfig("database", Constants.DATABASE_OBJECT.get(i) +
					"/property[@type='database.password']/@value");
			String dbStartup = Config.getDefault().parseConfig("database", Constants.DATABASE_OBJECT.get(i) +
					"/property[@type='database.startup']/@value");
			Driver dbDriver = null;
			
			for(Driver driver : Driver.values()) {
				if (driver.name().equals(dbType)) {
					dbDriver = driver;
					break;
				}
			}
			
			if (dbDriver == null) {
				warning("Database definition for '" + dbName + "' does not match a known database type of '" + dbType + "'");
			} else {
				try {
					RegistryContainer rContainer = null;
					
					if (dbUsername != null && !dbUsername.equals("")) {
						rContainer = new RegistryContainer(dbDriver, dbUrl, dbUsername, dbPassword);
						jdbcRegistry.put(dbName, rContainer);
					} else {
						rContainer = new RegistryContainer(dbDriver, dbUrl);
						jdbcRegistry.put(dbName, rContainer);
					}
					
					try {
						if (dbStartup != null && !dbStartup.equals("")) {
							Connection conn = rContainer.getConnection();
							Statement statement = conn.createStatement();
							
							statement.execute(dbStartup);
							statement.close();
							conn.close();
						}
					} catch(SQLException e) {
						warning("Startup SQL statement '" + dbStartup + "' in DB definition '" + dbName + "' failed: " +
								e.getMessage());
					}
					
					if (isDebugEnabled()) {
						debug("Database entry for '" + dbName + "' type '" + dbType + "' registered.");
					}
				} catch(DBException e) {
					warning("Unable to create database connection for '" + dbName + "' type '" + dbType + "' url '" + dbUrl +
							"': " + e.getMessage());
				}
			}
		}
	}
	
	public static final Registry getDefault() {
		return _default;
	}
	
	public Connection get(String name) {
		try {
			return jdbcRegistry.get(name).getConnection();
		} catch(DBException e) {
			if (isDebugEnabled()) {
				debug("Unable to return connection: " + e.getMessage());
			}
		}
		
		return null;
	}
}